import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;


public class Client {

	public Socket clientSocket;
	public DataOutputStream outToServer;
	public BufferedReader inFromServer;
	public ArrayBlockingQueue<String> queue;
	public ClientThread cthread;
	
	
	public static void main(String[] args) {
		Client c = new Client();
	}

	public Client() {

		//initialize
		queue = new ArrayBlockingQueue<String>(Global.queueSize);
		cthread = new ClientThread(queue);
		cthread.start();
		
		//pick a random server and initialize
		ArrayList<MachineData> machines = MachineData.getList(Global.filename);
		int N = machines.size();
		MachineData m = machines.get((int) (Math.random()*N));

		try {
			clientSocket = new Socket(m.ip, m.port, InetAddress.getByName("127.0.0.1"), Global.clientPort);
			outToServer = new DataOutputStream(clientSocket.getOutputStream());
			inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		//pick a key and value
		int key = 3;
		String value = "3";

		//send insert request
		insert(key, value, m);

		//m = machines.get((int) (Math.random()*N));
		//send get
		get(key, m);

		//m = machines.get((int) (Math.random()*N));
		//send delete
		delete(key,m);
		
		//shutdown
		cthread.flag = false;
		
		try {
			clientSocket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		System.exit(0);

	}

	public String get(int key, MachineData m) {
		//send request
		String message = "GET " + key;
		sendMessage(message, m);
		System.out.println(message + " " + m.port);
		
		//get confirmation
		String c = getConfirmation();
		System.out.println(c);

		return c;
	}

	public String insert(int key, String value, MachineData m) {
		//send request		
		String message = "INSERT " + key + " " + value;
		System.out.println(message + " " + m.port);
		System.out.println(message + " " + m.port);
		
		sendMessage(message, m);

		//get confirmation
		String c = getConfirmation();
		System.out.println(c);

		return c;
	}

	public String delete(int key, MachineData m) {
		//send request	
		String message = "DELETE " + key;
		sendMessage(message, m);
		System.out.println(message + " " + m.port);
		
		//get confirmation
		String c = getConfirmation();
		System.out.println(c);

		return c;
	}

	public void sendMessage(String message, MachineData m) {
		try {
			outToServer.writeBytes(message + '\n');
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public String getConfirmation() {

		while(queue.isEmpty()) {
		}
		
		try {
			return queue.take();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	private class ClientThread extends Thread {

		public ArrayBlockingQueue<String> queue;
		public ServerSocket socket;
		public boolean flag = true;
		
		public ClientThread(ArrayBlockingQueue<String> queue) {
			this.queue = queue;
		}

		public void run() {

			try {
				socket = new ServerSocket(Global.clientPortr);
			} catch (IOException e) {
				e.printStackTrace();
				System.exit(0);
			}

			while(flag) {
				try {
					Socket s = socket.accept();

					PrintWriter out = new PrintWriter(s.getOutputStream(),
							true);
					BufferedReader in = new BufferedReader(new InputStreamReader(
							s.getInputStream()));

					String data = in.readLine();

					queue.add(data);
				} catch (IOException e) {
					e.printStackTrace();
					System.exit(0);
				}
			}
			
			try {
				socket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
